package com.isoftstone.framework.shiro;


import com.isoftstone.common.constant.Constants;
import com.isoftstone.common.utils.JsonUtil;
import com.isoftstone.framework.domain.Tidings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


/**
 *
 */
@Slf4j
public final class MyFormAuthenticationFilter extends FormAuthenticationFilter {

    public static final String DEFAULT_USERNAME_PARAM = "userName";
    public static final String DEFAULT_PASSWORD_PARAM = "passWord";
    public static final String DEFAULT_CAPTCHA_PARAM = "vaildateCode";

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String username = WebUtils.getCleanParam(request, DEFAULT_USERNAME_PARAM);
        String password = WebUtils.getCleanParam(request, DEFAULT_PASSWORD_PARAM);
        return new UsernamePasswordToken(username, password);
    }

    /**
     * 登陆成功后
     *
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {

        HttpServletRequest request1 = (HttpServletRequest) request;
        HttpServletResponse response1 = (HttpServletResponse) response;
        if (!"XMLHttpRequest".equalsIgnoreCase(request1.getHeader("X-Requested-With"))) {
            issueSuccessRedirect(request, response);
            return true;
        } else {
            Tidings<String> tidings = new Tidings<String>();
            tidings.setStatus(Constants.SUCCESS);
            response1.setCharacterEncoding("utf-8");
            PrintWriter out = response1.getWriter();
            out.write(JsonUtil.beanToJson(tidings));
            out.flush();
            out.close();
            return true;
        }

    }

    /**
     * 所有所有请求都会经过
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

        if (this.isLoginRequest(request, response)) {
            if (this.isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("login submission detected attempting to execute login!");
                }
                return this.executeLogin(request, response);
            } else {
                return true;
            }
        } else {
            if (!isAjaxRequest((HttpServletRequest) request)) {  //不是AJAX请求
                this.saveRequestAndRedirectToLogin(request, response);
            } else {
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                HttpServletResponse req = (HttpServletResponse) response;
                req.setStatus(HttpStatus.OK.value());
                response.setCharacterEncoding("utf-8");
                PrintWriter writer = response.getWriter();
                writer.print("{\"status\":false,\"msg\":\"Unauthorized\",\"t\":\"401\"}");
                writer.flush();
                writer.close();
            }

            return false;
        }

    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (this.isLoginRequest(request, response)) {

            Subject subject = this.getSubject(request, response);

            boolean authenticated = subject.isAuthenticated();

            if (authenticated) {
                try {
                    issueSuccessRedirect(request, response);
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
            //如果是登陆方法 执行退出
            if (this.isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("login submission detected attempting to execute login!");
                }
                String username = this.getUsername(request);

                Object principal = subject.getPrincipal();

                if (StringUtils.isNotBlank(username) && username.equals(principal)) {
                    subject.logout();
                }
            }
        }

        return super.isAccessAllowed(request, response, mappedValue);
    }

    @Override
    public void setLoginUrl(String loginUrl) {
        super.setLoginUrl(loginUrl);
    }

    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        if (!isAjaxRequest((HttpServletRequest) request)) {
            setFailureAttribute(request, e);
            return true;
        }

        try {
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("utf-8");
            PrintWriter writer = response.getWriter();

            String msg = e.getClass().getSimpleName();
            String res = "";
            if (e.getCause() != null) {
                res = e.getCause().getClass().getSimpleName();
            }

            if ("IncorrectCredentialsException".equals(msg)) {
                writer.print("{\"status\":false,\"msg\":\"密码错误\",\"t\":\"500\"}");
            } else if ("UnknownAccountException".equals(msg)) {
                writer.print("{\"status\":false,\"msg\":\"账号不存在\",\"t\":\"500\"}");
            } else if ("MoreUsersException".equals(msg)) {
                writer.print("{\"status\":false,\"msg\":\"多个用户名，请联系重置\",\"t\":\"500\"}");
            } else if ("IncorrectCaptchaException".equals(msg)) {
                writer.print("{\"status\":false,\"msg\":\"验证码不正确\",\"t\":\"500\"}");
            } else {
                writer.print("{\"status\":false,\"msg\":\"账号或密码错误\",\"t\":\"500\"}");
            }

            writer.flush();
            writer.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        return false;
    }

    private boolean isAjaxRequest(HttpServletRequest request) {
        return "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"));
    }


}
